1 /*
2 * Copyright 2002-2012 the original author or authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.springframework.beans.factory.config;
18
19 import java.io.Serializable;
20
21 import org.springframework.beans.BeansException;
22 import org.springframework.beans.factory.BeanFactory;
23 import org.springframework.beans.factory.ObjectFactory;
24 import org.springframework.util.Assert;
25
26 /**
27 * A {@link org.springframework.beans.factory.FactoryBean} implementation that
28 * returns a value which is an {@link org.springframework.beans.factory.ObjectFactory}
29 * that in turn returns a bean sourced from a {@link org.springframework.beans.factory.BeanFactory}.
30 *
31 * <p>As such, this may be used to avoid having a client object directly calling
32 * {@link org.springframework.beans.factory.BeanFactory#getBean(String)} to get
33 * a (typically prototype) bean from a
34 * {@link org.springframework.beans.factory.BeanFactory}, which would be a
35 * violation of the inversion of control principle. Instead, with the use
36 * of this class, the client object can be fed an
37 * {@link org.springframework.beans.factory.ObjectFactory} instance as a
38 * property which directly returns only the one target bean (again, which is
39 * typically a prototype bean).
40 *
41 * <p>A sample config in an XML-based
42 * {@link org.springframework.beans.factory.BeanFactory} might look as follows:
43 *
44 * <pre class="code"><beans>
45 *
46 * <!-- Prototype bean since we have state -->
47 * <bean id="myService" class="a.b.c.MyService" scope="prototype"/>
48 *
49 * <bean id="myServiceFactory"
50 * class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
51 * <property name="targetBeanName"><idref local="myService"/></property>
52 * </bean>
53 *
54 * <bean id="clientBean" class="a.b.c.MyClientBean">
55 * <property name="myServiceFactory" ref="myServiceFactory"/>
56 * </bean>
57 *
58 *</beans></pre>
59 *
60 * <p>The attendant {@code MyClientBean} class implementation might look
61 * something like this:
62 *
63 * <pre class="code">package a.b.c;
64 *
65 * import org.springframework.beans.factory.ObjectFactory;
66 *
67 * public class MyClientBean {
68 *
69 * private ObjectFactory<MyService> myServiceFactory;
70 *
71 * public void setMyServiceFactory(ObjectFactory<MyService> myServiceFactory) {
72 * this.myServiceFactory = myServiceFactory;
73 * }
74 *
75 * public void someBusinessMethod() {
76 * // get a 'fresh', brand new MyService instance
77 * MyService service = this.myServiceFactory.getObject();
78 * // use the service object to effect the business logic...
79 * }
80 * }</pre>
81 *
82 * <p>An alternate approach to this application of an object creational pattern
83 * would be to use the {@link ServiceLocatorFactoryBean}
84 * to source (prototype) beans. The {@link ServiceLocatorFactoryBean} approach
85 * has the advantage of the fact that one doesn't have to depend on any
86 * Spring-specific interface such as {@link org.springframework.beans.factory.ObjectFactory},
87 * but has the disadvantage of requiring runtime class generation. Please do
88 * consult the {@link ServiceLocatorFactoryBean ServiceLocatorFactoryBean JavaDoc}
89 * for a fuller discussion of this issue.
90 *
91 * @author Colin Sampaleanu
92 * @author Juergen Hoeller
93 * @since 1.0.2
94 * @see org.springframework.beans.factory.ObjectFactory
95 * @see ServiceLocatorFactoryBean
96 */
97 public class ObjectFactoryCreatingFactoryBean extends AbstractFactoryBean<ObjectFactory<Object>> {
98
99 private String targetBeanName;
100
101
102 /**
103 * Set the name of the target bean.
104 * <p>The target does not <i>have</i> to be a non-singleton bean, but realistically
105 * always will be (because if the target bean were a singleton, then said singleton
106 * bean could simply be injected straight into the dependent object, thus obviating
107 * the need for the extra level of indirection afforded by this factory approach).
108 */
109 public void setTargetBeanName(String targetBeanName) {
110 this.targetBeanName = targetBeanName;
111 }
112
113 @Override
114 public void afterPropertiesSet() throws Exception {
115 Assert.hasText(this.targetBeanName, "Property 'targetBeanName' is required");
116 super.afterPropertiesSet();
117 }
118
119
120 @Override
121 public Class<?> getObjectType() {
122 return ObjectFactory.class;
123 }
124
125 @Override
126 protected ObjectFactory<Object> createInstance() {
127 return new TargetBeanObjectFactory(getBeanFactory(), this.targetBeanName);
128 }
129
130
131 /**
132 * Independent inner class - for serialization purposes.
133 */
134 @SuppressWarnings("serial")
135 private static class TargetBeanObjectFactory implements ObjectFactory<Object>, Serializable {
136
137 private final BeanFactory beanFactory;
138
139 private final String targetBeanName;
140
141 public TargetBeanObjectFactory(BeanFactory beanFactory, String targetBeanName) {
142 this.beanFactory = beanFactory;
143 this.targetBeanName = targetBeanName;
144 }
145
146 @Override
147 public Object getObject() throws BeansException {
148 return this.beanFactory.getBean(this.targetBeanName);
149 }
150 }
151
152 }